use std::{
    collections::VecDeque, path::Path
};

use regex::Regex;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sqlx::{sqlite::SqliteRow, Row};

use crate::{
    APP_DIR, dao::config, utils::{
        date_util::{
            self, extract_time_from_string, get_now_time_m,
            parse_time_string,
        },
        file_util::{self, ensure_parent_dir_exists},
        mysql_utils::get_connect, tree::TreeNode,
    }
};

pub const PREVIEW_NUM: usize = 2;

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct FileInfo {
    pub name: String,
    pub path: String,
}

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Momento {
    pub id: String,
    pub pid: Option<String>,
    pub pids: String,
    pub book_id: String,
    pub is_folder: i16,
    pub date: i64,
    pub file_path: String,
    pub note_content: String,
    pub heading: String,
    pub preview: String,
    pub title: String,
    pub files: Vec<FileInfo>,
    pub open_type: String,
    pub add_date: String,
    pub create_time: i64,
    pub creator_lid: String,
    pub creator_name: String,
    pub updater_lid: String,
    pub updater_name: String,
    pub up_ver: i16,
    pub sort: i16,
    pub tenant_id: i64,
    pub deleted: i64,
    pub update_time: i64,
}

impl Default for Momento {
    fn default() -> Self {
        Momento {
            id: "0".to_string(),
            date: 0,
            file_path: String::from(""),
            note_content: String::from(""),
            heading: String::from(""),
            preview: String::from(""),
            title: String::from(""),
            files: vec![],
            open_type: String::from(""),
            add_date: String::from(""),
            create_time: 0,
            creator_lid: String::from(""),
            creator_name: String::from(""),
            updater_lid: String::from(""),
            updater_name: String::from(""),
            up_ver: 0,
            sort: -1,
            tenant_id: 0,
            deleted: 0,
            update_time: 0,
            pid: None,
            pids: String::from(""),
            book_id: String::from(""),
            is_folder: 0,
        }
    }
}

impl TreeNode for Momento {
    type Id = String;
    fn id(&self) -> Self::Id {
        self.id.clone()
    }
    
    fn parent_id(&self) -> Option<Self::Id> {
        self.pid.clone()
    }
    
    fn get_parent_ids(&self) -> Vec<Self::Id> {
        if self.pids.is_empty() {
            return vec![];
        }
        self.pids.split(',').map(|s| s.to_string()).collect()
    }
}


pub async fn get_info_by_id(id: String) -> Option<Momento> {
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let rust =
        sqlx::query("select id, date, title, note_content, create_time, update_time, heading, preview, file_path, files, add_date, book_id, pid, is_folder, pids, open_type from momento where id = ?")
            .bind(id)
            .map(|row: SqliteRow| {
                let mut momento = Momento::default();
                momento.id = row.get(0);
                momento.date = row.get(1);
                momento.title = row.get(2);
                momento.note_content = row.get(3);
                momento.create_time = row.get(4);
                momento.update_time = row.get(5);
                momento.heading = row.get(6);
                momento.preview = row.get(7);
                momento.file_path = row.get(8);
                let files: String = row.get(9);
                if !files.is_empty() {
                    if let Ok(files) = serde_json::from_str(&files) {
                        momento.files = files;
                    }
                }
                momento.add_date = row.get(10);
                momento.book_id = row.get(11);
                momento.pid = row.get(12);
                momento.is_folder = row.get(13);
                momento.pids = row.get(14);
                momento.open_type = row.get(15);
                momento
            })
            .fetch_all(&mut *conn)
            .await;
    match rust {
        Ok(rest) => {
            if let Some(res) = rest.get(0) {
                return Some(res.clone());
            }
            return None;
        }
        Err(e) => {
            log::info!("失败{}", e);
            return None;
        }
    }
}


pub async fn get_list_by_book_id(book_id: String, mut pid: String, mut title: String, is_folder: Option<i16>) -> Option<Vec<Momento>> {
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let mut sql = "select id, date, title, note_content, create_time, update_time, heading, preview, file_path, files, add_date, book_id, pid, is_folder, pids, sort from momento where 1=1".to_string();
    if !book_id.is_empty() {
        if book_id == "1" {
            sql += " and (book_id = ? or book_id is null or book_id = '' )";
        } else {
            sql += " and book_id = ?";
        }
    }
    if !pid.is_empty() {
        pid = format!("%{}%", pid);
        sql += " and pids like ? "
    }
    if !title.is_empty() {
        title = format!("%{}%", title);
        sql += " and title like ?";
    }
    if !is_folder.is_none() {
             sql += " and is_folder = ?";
    }
    sql += " order by sort asc, id DESC;";
    println!("sql {}", sql);
    println!("params: book_id = {}. pid = {}", book_id, pid);
    let mut query = sqlx::query(sql.as_str());
    if !book_id.is_empty() {
        query = query.bind(book_id);
    }
    if !pid.is_empty() {
        query = query.bind(pid);
    }
    if !title.is_empty() {
        query = query.bind(title);
    }
    if !is_folder.is_none() {
        query = query.bind(is_folder);
    }
    let rust = query
        .map(|row: SqliteRow| {
            let mut momento = Momento::default();
            momento.id = row.get(0);
            momento.date = row.get(1);
            momento.title = row.get(2);
            momento.note_content = row.get(3);
            momento.create_time = row.get(4);
            momento.update_time = row.get(5);
            momento.heading = row.get(6);
            momento.preview = row.get(7);
            momento.file_path = row.get(8);
            let files: String = row.get(9);
            if !files.is_empty() {
                if let Ok(files) = serde_json::from_str(&files) {
                    momento.files = files;
                }
            }
            momento.add_date = row.get(10);
            momento.book_id = row.get(11);
            momento.pid = row.get(12);
            momento.is_folder = row.get(13);
            momento.pids = row.get(14);
            momento.sort = row.get(15);
            momento
        })
        .fetch_all(&mut *conn)
        .await;
    match rust {
        Ok(rest) => {
            return Some(rest);
        }
        Err(e) => {
            log::info!("失败{}", e);
            return None;
        }
    }
}


pub async fn get_list() -> Option<Vec<Momento>> {
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let rust = sqlx::query("select id, date, title, note_content, create_time, update_time, heading, preview, file_path, files, add_date, book_id, pid, is_folder from momento")
        .map(|row: SqliteRow| {
            let mut momento = Momento::default();
            momento.id = row.get(0);
            momento.date = row.get(1);
            momento.title = row.get(2);
            momento.note_content = row.get(3);
            momento.create_time = row.get(4);
            momento.update_time = row.get(5);
            momento.heading = row.get(6);
            momento.preview = row.get(7);
            momento.file_path = row.get(8);
            let files: String = row.get(9);
            if !files.is_empty() {
                if let Ok(files) = serde_json::from_str(&files) {
                    momento.files = files;
                }
            }
            momento.add_date = row.get(10);
            momento.book_id = row.get(11);
            momento.pid = row.get(12);
            momento.is_folder = row.get(13);
            momento
        })
        .fetch_all(&mut *conn)
        .await;
    match rust {
        Ok(rest) => {
            return Some(rest);
        }
        Err(e) => {
            log::info!("失败{}", e);
            return None;
        }
    }
}


pub async fn get_tree(book_id: String, pid: String, is_folder: Option<i16>) -> Option<Value> {
    if let Some(list) = get_list_by_book_id(book_id, pid, "".to_string(), is_folder).await {
        let tree = crate::utils::tree::build_wrapped_tree(&list);
        // 测试 JSON 序列化
        let json_obj: Result<Value, serde_json::Error> = tree.to_value();
        assert!(json_obj.is_ok());
        let json_obj = json_obj.unwrap();
        return Some(json_obj);
    }
    return None;
}


pub async fn exit_pids(root: Value) {
    let mut queue = VecDeque::new();
    queue.push_back(root);
    while let Some(value) = queue.pop_front() {
        // 处理数组情况
        if let Some(array) = value.as_array() {
            for item in array {
                queue.push_back(item.clone());
            }
            continue;
        }
        // 处理对象情况
        let current_pids = match value.get("pids").and_then(|v| v.as_str()) {
            Some(p) => p,
            None => {
                // 将子节点加入队列
                if let Some(children) = value.get("children").and_then(|v| v.as_array()) {
                    for child in children {
                        queue.push_back(child.clone());
                    }
                }
                continue;
            }
        };

        // 比较pids和parent_ids
        if let Some(ids) = value.get("parent_ids").and_then(|v| v.as_array()) {
            let pids_vec: Vec<&str> = current_pids.split(',').collect();
            let is_same = pids_vec.len() != 0 && ids.len() != 0 && pids_vec.len() == ids.len() 
                && pids_vec.iter().zip(ids.iter()).all(|(pid, parent_id)| {
                    pid == &parent_id.as_str().unwrap_or("")
                });
            if !is_same {
                println!("pids 和 parent_ids 不同，进行更新");
                let data: Result<Momento, serde_json::Error> = serde_json::from_value(value.clone());
                match data {
                    Ok(mut info) => {
                        if ids.is_empty() {
                            info.pids = info.pid.clone().unwrap();
                        } else {
                            info.pids = ids.iter()
                            .filter_map(|id| id.as_str())
                            .collect::<Vec<&str>>()
                            .join(",");
                        }
                        println!("更新：{}", info.pids);
                        update_tokio(info).await;
                    },
                    Err(_) => {
                        log::error!("转换 Momento 失败，无法更新 pids");
                        continue;
                    },
                }
            }
        }
        // 将子节点加入队列
        if let Some(children) = value.get("children").and_then(|v| v.as_array()) {
            for child in children {
                queue.push_back(child.clone());
            }
        }
    }
}


pub async fn get_page(page_num: u32, page_size: u32, mut title: String) -> Option<Vec<Momento>> {
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let mut sql = String::from(
        "select id, date, title, note_content, create_time, update_time, heading, preview, file_path, files, add_date, book_id, pid, is_folder from momento",
    );
    if !title.is_empty() {
        title = format!("%{}%", title);
        sql += " where title like ?";
    }
    sql += " order by create_time desc limit ?,? ";
    let mut query = sqlx::query(sql.as_str());
    if !title.is_empty() {
        query = query.bind(title);
    }
    let last = page_num * page_size;
    query = query.bind(last - page_size).bind(page_size);
    log::info!("{}   {}", last - page_size, last);
    let rust = query
        .map(|row: SqliteRow| {
            let mut momento = Momento::default();
            momento.id = row.get(0);
            momento.date = row.get(1);
            momento.title = row.get(2);
            momento.note_content = row.get(3);
            momento.create_time = row.get(4);
            momento.update_time = row.get(5);
            momento.heading = row.get(6);
            momento.preview = row.get(7);
            momento.file_path = row.get(8);
            let files: String = row.get(9);
            if !files.is_empty() {
                if let Ok(files) = serde_json::from_str(&files) {
                    momento.files = files;
                }
            }
            momento.add_date = row.get(10);
            momento.book_id = row.get(11);
            momento.pid = row.get(12);
            momento.is_folder = row.get(13);
            momento
        })
        .fetch_all(&mut *conn)
        .await;
    match rust {
        Ok(rest) => {
            log::info!("size  {}", rest.len());
            return Some(rest);
        }
        Err(e) => {
            log::info!("失败{}", e);
            return None;
        }
    }
}


pub async fn get_count(mut title: String) -> Option<i64> {
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let mut sql = String::from("select COUNT(*) from momento");
    if !title.is_empty() {
        title = format!("%{}%", title);
        sql += " and title like ?";
    }
    let mut query = sqlx::query_as(sql.as_str());
    if !title.is_empty() {
        query = query.bind(title);
    }
    let rust: Result<(i64,), sqlx::Error> = query.fetch_one(&mut *conn).await;
    match rust {
        Ok((rest,)) => {
            return Some(rest);
        }
        Err(e) => {
            log::info!("失败{}", e);
            return None;
        }
    }
}


#[tokio::main]
pub async fn save(mut info: Momento) -> bool {
    let pid  = info.pid.clone();
    if pid.is_none() {
        log::info!("pid 不能为空");
        return false;
    }
    let pid = pid.unwrap();
    info.pids = set_pids(pid, info.pids.clone(), info.book_id.clone()).await;
    info.file_path = set_file_path(info.id.clone(), info.file_path.clone());
    let (content, list, _is_up) = set_files(info.note_content.clone());
    info.note_content = content.clone();
    let mut file_list_str = String::from("");
    if let Ok(text) = serde_json::to_string(&list) {
        file_list_str = text;
    }
    if !content.is_empty() {
        if content.chars().count() > PREVIEW_NUM {
            info.preview = content.chars().take(PREVIEW_NUM).collect();
        } else {
            info.preview = content.clone();
        }
    }
    let file_path = info.file_path;
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let now = get_now_time_m();
    let result = sqlx::query("insert into momento (id,pid, pids, book_id, is_folder, file_path,preview,heading,title,files, add_date,date,create_time,creator_lid,creator_name,updater_lid,updater_name,up_ver,sort,tenant_id,deleted,update_time) values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)")
    .bind(info.id)
    .bind(info.pid)
    .bind(info.pids)
    .bind(info.book_id)
    .bind(info.is_folder)
    .bind(file_path.clone())
    .bind(info.preview)
    .bind(info.heading)
    .bind(info.title)
    .bind(file_list_str)
    .bind(date_util::get_ymd_str_by_m(now))
    .bind(now)
    .bind(now)
    .bind(info.creator_lid)
    .bind(info.creator_name)
    .bind(info.updater_lid)
    .bind(info.updater_name)
    .bind(info.up_ver)
    .bind(info.sort)
    .bind(info.tenant_id)
    .bind(info.deleted)
    .bind(now)
    .execute(&mut *conn)
    .await;

    match result {
        Ok(_) => {
            write_content_file(file_path, content.clone()).await;
            log::info!("创建数据成功");
            return true;
        }
        Err(e) => {
            log::info!("{}", e);
            log::info!("创建数据失败");
            return false;
        }
    }
}


/// 假定 Momento 定义、get_info_by_id、get_connect、file_util、ensure_parent_dir_exists、
/// FILE_DOC_PATH、PREVIEW_NUM、get_ym_str、get_now_time_m 等在别处已定义并可用。

pub async fn update_tokio(mut info: Momento) -> Option<bool> {
    let pid  = info.pid.clone();
    if !pid.is_none() {
        let pid = pid.unwrap();
        // pid处理
        info.pids = set_pids(pid, info.pids.clone(), info.book_id.clone()).await;
    }

    info.file_path = set_file_path(info.id.clone(), info.file_path.clone());
    if info.note_content.is_empty() {
        let (content, list, _is_up) = set_files(info.note_content.clone());
        info.note_content = content.clone();
        info.files = list;
        // 写文件并删除旧文件
        write_content_file(info.file_path.clone(), content.clone()).await;
    }

    // ------- 4) 更新数据库 -------
    let result = update(info).await ;
    match result {
        Some(_) => {

            log::info!("更新数据成功");
            return Some(true);
        },
        None => {
            log::info!("更新数据失败");
            return None;
        }
    }
    
}


pub async fn update_content_tokio(mut info: Momento) -> bool {
    info.file_path = set_file_path(info.id.clone(), info.file_path.clone());
    let file_path = info.file_path.clone();
    let content = info.note_content.clone();
    // ------- 4) 更新数据库 -------
    let result = update(info).await ;
    match result {
        Some(_) => {
            write_content_file(file_path, content).await;
            log::info!("更新数据成功");
            return true;
        },
        None => {
            log::info!("更新数据失败");
            return false;
        }
    }
}


pub async fn update_momento_title_heading(info: Momento) -> Option<bool> {
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let now = get_now_time_m();
    let result = sqlx::query("UPDATE momento SET title = ?, heading = ?, update_time = ?  where id = ?")
        .bind(info.title)
        .bind(info.heading)
        .bind(now)
        .bind(info.id)
        .execute(&mut *conn)
        .await;
    match result {
        Ok(_) => {
            log::info!("更新数据成功");
            return Some(true);
        }
        Err(e) => {
            log::info!("更新数据失败: {}", e);
            return None;
        }
    }
}


pub async fn update_sort_tokio(mut info: Momento) -> Option<bool> {
    let pid  = info.pid.clone();
    if !pid.is_none() {
        let pid = pid.unwrap();
        // pid处理
        info.pids = set_pids(pid, info.pids.clone(), info.book_id.clone()).await;
    }
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let now = get_now_time_m();
    //log::info!("更新sql {}", sql);
    let result = sqlx::query("UPDATE momento SET pid = ?, pids = ?, book_id = ?, sort = ?, update_time = ?  where id = ?")
        .bind(info.pid)
        .bind(info.pids)
        .bind(info.book_id)
        .bind(info.sort)
        .bind(now)
        .bind(info.id)
        .execute(&mut *conn)
        .await;
    match result {
        Ok(_) => {
            log::info!("更新数据成功");
            return Some(true);
        }
        Err(e) => {
            log::info!("更新数据失败: {}", e);
            return None;
        }
    }
}


pub async fn update(mut info: Momento) -> Option<bool> {
    //log::info!("update 更新：{:?}", info);
    // ------- 4) 更新数据库 -------
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let now = get_now_time_m();

    if info.note_content.len() > PREVIEW_NUM {
        info.note_content = info.note_content.chars().take(PREVIEW_NUM).collect();
    }

    let mut sql = "UPDATE momento SET update_time = ? ".to_string();
    if !info.title.is_empty() {
        sql += " ,title = ? ";
    }
    if !info.pid.is_none() {
        sql += " ,pid = ? ";
    }
    if !info.pids.is_empty() {
        sql += " ,pids = ? ";
    }
    if !info.book_id.is_empty() {
        sql += " ,book_id = ? ";
    }
    if !info.file_path.is_empty() {
        sql += " ,file_path = ? ";
    }
    if !info.heading.is_empty() {
        sql += " ,heading = ? ";
    }
    if !info.files.is_empty() {
        sql += " ,files = ? ";
    }
    if !info.note_content.is_empty() {
        sql += " ,note_content = ? ";
    }
    if !info.preview.is_empty() {
        sql += " ,preview = ? ";
    }
    if info.sort >= 0 {
        sql += " ,sort = ? ";
    }
    if !info.open_type.is_empty() {
        sql += " ,open_type = ? ";
    }
    sql += " WHERE id = ?";
    //log::info!("更新sql {}", sql);
    let mut result = sqlx::query(&sql);
    result = result.bind(now);
    if !info.title.is_empty() {
        result = result.bind(info.title);
    }
    if !info.pid.is_none() {
        result = result.bind(info.pid);
    }
    if !info.pids.is_empty() {
        result = result.bind(info.pids);
    }
    if !info.book_id.is_empty() {
        result = result.bind(info.book_id);
    }
    if !info.file_path.is_empty() {
        result = result.bind(info.file_path);
    }
    if !info.heading.is_empty() {
        result = result.bind(info.heading);
    }
    if !info.files.is_empty() {
        let mut file_list_str = String::new();
        if let Ok(text) = serde_json::to_string(&info.files) {
            file_list_str = text;
        }
        result = result.bind(file_list_str);
    }
    if !info.note_content.is_empty() {
        result = result.bind(info.note_content);
    }
    if !info.preview.is_empty() {
        result = result.bind(info.preview);
    }
    if info.sort >= 0 {
        result = result.bind(info.sort);
    }
    if !info.open_type.is_empty() {
        result = result.bind(info.open_type);
    }
    let result = result.bind(info.id)
        .execute(&mut *conn)
        .await;
    match result {
        Ok(_) => {
            log::info!("更新数据成功");
            return Some(true);
        }
        Err(e) => {
            log::info!("更新数据失败: {}", e);
            return None;
        }
    }
}


pub async fn delete_by_id(id: String) -> bool {
    log::info!("{}", id);
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    println!("{}", id);
    let result = sqlx::query("delete from momento where id = ?")
        .bind(id)
        .execute(&mut *conn)
        .await;

    match result {
        Ok(_) => {
            println!("删除数据成功 {:?}", result);
            return true;
        }
        Err(e) => {
            println!("{}", e);
            println!("删除数据失败");
            return false;
        }
    }
}


pub async fn get_count_by_book_id(book_id: String) -> Option<bool> {
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let rust: Result<(i64,), sqlx::Error> = sqlx::query_as("select COUNT(*) from momento where book_id = ?").bind(book_id).fetch_one(&mut *conn).await;
    match rust {
        Ok((rest,)) => {
            if rest > 0 {
                return Some(true);
            }
            return Some(false);
        }
        Err(e) => {
            log::info!("失败{}", e);
            return None;
        }
    }
}


pub async fn get_count_by_pid(pid: String) -> Option<bool> {
    let mut conn = get_connect()
        .acquire()
        .await
        .expect("Error get_connect from db pool");
    let rust: Result<(i64,), sqlx::Error> = sqlx::query_as("select COUNT(*) from momento where pid = ?").bind(pid).fetch_one(&mut *conn).await;
    match rust {
        Ok((rest,)) => {
            if rest > 0 {
                return Some(true);
            }
            return Some(false);
        }
        Err(e) => {
            log::info!("失败{}", e);
            return None;
        }
    }
}


pub fn str_to_momento(mut text: String) -> Option<Momento> {
    let mut momento = Momento::default();
    let times = extract_time_from_string(&text);
    let mut time = "";
    if times.len() > 0 {
        time = times.first().unwrap();
        text = text.replace(time, "").trim().to_owned();
    }
    if !time.is_empty() {
        log::info!("---{}", time);
        let time = parse_time_string(time);
        match time {
            Some(time) => {
                momento.date = time.and_utc().timestamp();
                log::info!("---{}", time);
            }
            None => {
                log::info!("没有提取到时间")
            }
        }
    }

    let mut splits = text.split(" ");
    let mut min = 0;
    let mut min_str = "";
    let len = splits.clone().count();
    if len > 3 {
        min_str = splits.next().unwrap();
    } else {
        for ele in splits {
            if !ele.trim().is_empty() {
                if min == 0 || min > (ele.len() as i32) {
                    min = ele.len() as i32;
                    min_str = ele;
                }
            }
        }
    }

    momento.title = min_str.to_string();
    println!("{}", len);
    if len == 1 {
        momento.note_content = text.clone();
    } else {
        // 克隆 text，避免修改时借用
        let mut new_text = text.clone();
        new_text = new_text.replace(min_str, "").trim().to_string();
        momento.note_content = new_text;
    }
    Some(momento)
}


//设置pids
async fn set_pids(pid: String, mut pids: String, book_id: String) -> String {
    // pid处理
    if !pid.is_empty() {
        if pids.is_empty() {
            // ------- 1) 迭代向上查找父链，避免递归 async 调用 -------
            // 我们从直接父 id 开始，依次查找父的父，收集 id 列表（从最近父级到最顶层）
            let mut collected: Vec<String> = Vec::new();
            let mut cur = Some(pid.clone());
            // 当能够根据 id 查到节点时，推入该节点的 id，然后继续追溯其 parent_id
            while let Some(cur_id) = cur {
                match get_info_by_id(cur_id.clone()).await {
                    Some(parent_data) => {
                        //println!("parent_data========= {:?}", parent_data);
                        // 将该父节点 id 推入链（将 id 转为字符串，和你的原逻辑保持一致）
                        collected.push(parent_data.id.clone());
                        // 继续追溯：若父节点还有 parent，则继续，否则退出
                        cur = parent_data.pid.clone();
                    }
                    None => {
                        // 找不到节点，停止追溯
                        break;
                    }
                }
            }
            collected.push(book_id);
            if collected.is_empty() {
                // 如果没有找到父链（例如父节点不存在），把 pid 本身作为 pids（与原逻辑一致）
                pids = pid.clone();
            } else {
                // 将向量用逗号连接为字符串（最近父级在前）
                pids = collected.join(",");
            }
            log::info!("计算得到 pids = {}", pids);        
        }
    }
    return pids;
}


//设置pids
pub fn set_file_path(id: String, mut file_path: String) -> String {
    if file_path.is_empty() && !id.is_empty() {
        file_path = "/doc/".to_string() + &date_util::get_ym_str() + "/" + &id.to_string() + ".md";
    }
    return file_path;
}


//提取内容中的temp文件
pub fn set_files(mut note_content: String) -> (String, Vec<FileInfo>, bool) {
    if note_content.is_empty() {
        return (note_content, vec![], false);
    }
    let mut is_up = false;
    let re = Regex::new(r"\[([^\]]+)\]\(([^)]+)\)").unwrap();
    let list: Vec<FileInfo> = re
        .captures_iter(&note_content.clone())
        .map(|caps| {
            let mut path = caps.get(2).unwrap().as_str().to_string();
            if path.contains("temp") {
                is_up = true;
                let path_temp = path.clone();
                if let Ok(decoded) = urlencoding::decode(&path) {
                    path = decoded.into_owned();
                }
                let new_path_temp = path.replace("temp", "img");
                path = path.replace("http://asset.localhost/", "");
                path = path.replace("asset://localhost/", "");
                let new_path = path.replace("temp", "img");
                log::info!("文件路径：{}", path);
                log::info!("目标路径：{}", new_path);
                // 确保父目录存在
                let _ = ensure_parent_dir_exists(&new_path);
                if Path::new(&path).exists() {
                    log::info!("复制文件！");
                    match std::fs::copy(&path, &new_path) {
                        Ok(_) => {
                            file_util::remove_file(&path);
                            log::info!("复制成功！");
                            path = new_path.to_string();
                        }
                        Err(_) => {
                            log::error!("复制失败，等待下次处理： {}", path);
                        }
                    }
                } else {
                    path = new_path.to_string();
                }
                // 源文件不存在，也把 URL 替换为目标地址（方便前端使用）
                note_content = note_content.replace(
                    &path_temp,
                    &new_path_temp,
                );
            }
            FileInfo {
                name: caps.get(1).unwrap().as_str().to_string(),
                path,
            }
        })
        .collect();
    return (note_content, list, is_up);
}


async fn write_content_file(mut file_path: String, content: String) {
    if file_path.is_empty() {
        log::error!("文件路径未生成！");
        return;
    }
    if !file_path.starts_with("doc") {
        let dic_path;
        match config::get_dic_path().await {
            Some(path) => {
                dic_path = path;
            },
            None => {
                dic_path = APP_DIR.get().unwrap().to_string();
                config::up_dir_config(dic_path.clone()).await;
            },
        }
        file_path = dic_path + &file_path.clone();
    }
    // 写文件并删除旧文件
    if let Some(ok) = file_util::write_file(file_path, content.clone()) {
        if ok {
            log::info!("更新moment，写文件成功！")
        } else {
            log::info!("更新moment，写文件失败！")
        }
    }
}